`timescale 1ns/100ps

module cm_fft2_N4 #(
    parameter C_DATA_WITH = 16
)(
    input  wire                     I_sys_clk,       // 工作时钟 100M
    input  wire                     I_data_start,    // 数据开始进入标志，与第一个数据对齐输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real,  // 数据输入，从start开始连续输入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag,  // 数据输入，从start开始连续输入
    output wire                     O_data_start,    // 数据开始输出标志与第一个数据对齐输出
    output wire [C_DATA_WITH+1:0]   O_data_out_real, // 数据输出，从start开始连续输出
    output wire [C_DATA_WITH+1:0]   O_data_out_imag  // 数据输出，从start开始连续输出
);

// ============================================================
// 内部参数
// ============================================================
/// W04=1
/// W14=-j

// ============================================================
// 变量声明
// ============================================================
reg                     S_data_start_d1;
reg                     S_data_start_d2;
reg                     S_data_start_d3;
reg                     S_data_start_d4;
reg                     S_data_start_d5;
reg [C_DATA_WITH-1:0]   S_data_in_real_d1;
reg [C_DATA_WITH-1:0]   S_data_in_real_d2;
reg [C_DATA_WITH-1:0]   S_data_in_real_d3;
reg [C_DATA_WITH-1:0]   S_data_in_real_d4;
reg [C_DATA_WITH-1:0]   S_data_in_real_d5;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d1;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d2;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d3;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d4;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d5;

reg [C_DATA_WITH:0]     S_data_out_real;  // x1 X2
reg [C_DATA_WITH:0]     S_data_out_imag;  // x1 X2

// ============================================================
// 主逻辑代码
// ============================================================

// 同步输入的 start 标志
always @(posedge I_sys_clk) begin
    S_data_start_d1 <= I_data_start;
    S_data_start_d2 <= S_data_start_d1;
    S_data_start_d3 <= S_data_start_d2;
    S_data_start_d4 <= S_data_start_d3;
    S_data_start_d5 <= S_data_start_d4;
end

// 缓存输入数据
always @(posedge I_sys_clk) begin
    S_data_in_real_d1 <= I_data_in_real;
    S_data_in_real_d2 <= S_data_in_real_d1;
    S_data_in_real_d3 <= S_data_in_real_d2;
    S_data_in_real_d4 <= S_data_in_real_d3;
    S_data_in_real_d5 <= S_data_in_real_d4;

    S_data_in_imag_d1 <= I_data_in_imag;
    S_data_in_imag_d2 <= S_data_in_imag_d1;
    S_data_in_imag_d3 <= S_data_in_imag_d2;
    S_data_in_imag_d4 <= S_data_in_imag_d3;
    S_data_in_imag_d5 <= S_data_in_imag_d4;
end

// 输出逻辑
always @(posedge I_sys_clk) begin
    if (S_data_start_d4) begin
        // (x(n)-x(n+N/2))*W04 = (x(n)-x(n+N/2))
        S_data_out_real <= {S_data_in_real_d4[C_DATA_WITH-1], S_data_in_real_d4} - 
                           {S_data_in_real_d2[C_DATA_WITH-1], S_data_in_real_d2};
        S_data_out_imag <= {S_data_in_imag_d4[C_DATA_WITH-1], S_data_in_imag_d4} - 
                           {S_data_in_imag_d2[C_DATA_WITH-1], S_data_in_imag_d2};
    end 
    else if (S_data_start_d5) begin
        // (x(n)-x(n+N/2))*W14 = (x(n)-x(n+N/2))*(-j) = (x(n+N/2)-x(n))*j
        S_data_out_real <= {S_data_in_imag_d2[C_DATA_WITH-1], S_data_in_imag_d2} - 
                           {S_data_in_imag_d4[C_DATA_WITH-1], S_data_in_imag_d4};
        S_data_out_imag <= {S_data_in_real_d2[C_DATA_WITH-1], S_data_in_real_d2} - 
                           {S_data_in_real_d4[C_DATA_WITH-1], S_data_in_real_d4};
    end 
    else begin
        // x(n)+x(n+N/2)  x(0)+x(2)
        S_data_out_real <= {S_data_in_real_d2[C_DATA_WITH-1], S_data_in_real_d2} + 
                           {I_data_in_real[C_DATA_WITH-1], I_data_in_real};
        S_data_out_imag <= {S_data_in_imag_d2[C_DATA_WITH-1], S_data_in_imag_d2} + 
                           {I_data_in_imag[C_DATA_WITH-1], I_data_in_imag};
    end
end

// 子模块实例化：cm_fft2_N2
cm_fft2_N2 #(
    .C_DATA_WITH(C_DATA_WITH + 1)
) u0_cm_fft2_N2 (
    .I_sys_clk          (I_sys_clk),                    // 工作时钟 100M
    .I_data_start       (S_data_start_d3 | S_data_start_d5), // 数据开始进入标志
    .I_data_in_real     (S_data_out_real),              // 数据输入
    .I_data_in_imag     (S_data_out_imag),              // 数据输入
    .O_data_start       (),                             // 数据开始输出标志
    .O_data_out_real    (O_data_out_real),              // 数据输出
    .O_data_out_imag    (O_data_out_imag)               // 数据输出
);

// 输出 start 标志
assign O_data_start = S_data_start_d5;

endmodule